home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / hplip / base / exif.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2009-10-28  |  26KB  |  907 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. FIELD_TYPES = ((0, 'X', 'Proprietary'), (1, 'B', 'Byte'), (1, 'A', 'ASCII'), (2, 'S', 'Short'), (4, 'L', 'Long'), (8, 'R', 'Ratio'), (1, 'SB', 'Signed Byte'), (1, 'U', 'Undefined'), (2, 'SS', 'Signed Short'), (4, 'SL', 'Signed Long'), (8, 'SR', 'Signed Ratio'))
  5. EXIF_TAGS = {
  6.     256: ('ImageWidth',),
  7.     257: ('ImageLength',),
  8.     258: ('BitsPerSample',),
  9.     259: ('Compression', {
  10.         1: 'Uncompressed TIFF',
  11.         6: 'JPEG Compressed' }),
  12.     262: ('PhotometricInterpretation',),
  13.     266: ('FillOrder',),
  14.     269: ('DocumentName',),
  15.     270: ('ImageDescription',),
  16.     271: ('Make',),
  17.     272: ('Model',),
  18.     273: ('StripOffsets',),
  19.     274: ('Orientation',),
  20.     277: ('SamplesPerPixel',),
  21.     278: ('RowsPerStrip',),
  22.     279: ('StripByteCounts',),
  23.     282: ('XResolution',),
  24.     283: ('YResolution',),
  25.     284: ('PlanarConfiguration',),
  26.     296: ('ResolutionUnit', {
  27.         1: 'Not Absolute',
  28.         2: 'Pixels/Inch',
  29.         3: 'Pixels/Centimeter' }),
  30.     301: ('TransferFunction',),
  31.     305: ('Software',),
  32.     306: ('DateTime',),
  33.     315: ('Artist',),
  34.     318: ('WhitePoint',),
  35.     319: ('PrimaryChromaticities',),
  36.     342: ('TransferRange',),
  37.     512: ('JPEGProc',),
  38.     513: ('JPEGInterchangeFormat',),
  39.     514: ('JPEGInterchangeFormatLength',),
  40.     529: ('YCbCrCoefficients',),
  41.     530: ('YCbCrSubSampling',),
  42.     531: ('YCbCrPositioning',),
  43.     532: ('ReferenceBlackWhite',),
  44.     33421: ('CFARepeatPatternDim',),
  45.     33422: ('CFAPattern',),
  46.     33423: ('BatteryLevel',),
  47.     33432: ('Copyright',),
  48.     33434: ('ExposureTime',),
  49.     33437: ('FNumber',),
  50.     33723: ('IPTC/NAA',),
  51.     34665: ('ExifOffset',),
  52.     34675: ('InterColorProfile',),
  53.     34850: ('ExposureProgram', {
  54.         0: 'Unidentified',
  55.         1: 'Manual',
  56.         2: 'Program Normal',
  57.         3: 'Aperture Priority',
  58.         4: 'Shutter Priority',
  59.         5: 'Program Creative',
  60.         6: 'Program Action',
  61.         7: 'Portrait Mode',
  62.         8: 'Landscape Mode' }),
  63.     34852: ('SpectralSensitivity',),
  64.     34853: ('GPSInfo',),
  65.     34855: ('ISOSpeedRatings',),
  66.     34856: ('OECF',),
  67.     36864: ('ExifVersion', (lambda x: ''.join(map(chr, x)))),
  68.     36867: ('DateTimeOriginal',),
  69.     36868: ('DateTimeDigitized',),
  70.     37121: ('ComponentsConfiguration', {
  71.         0: '',
  72.         1: 'Y',
  73.         2: 'Cb',
  74.         3: 'Cr',
  75.         4: 'Red',
  76.         5: 'Green',
  77.         6: 'Blue' }),
  78.     37122: ('CompressedBitsPerPixel',),
  79.     37377: ('ShutterSpeedValue',),
  80.     37378: ('ApertureValue',),
  81.     37379: ('BrightnessValue',),
  82.     37380: ('ExposureBiasValue',),
  83.     37381: ('MaxApertureValue',),
  84.     37382: ('SubjectDistance',),
  85.     37383: ('MeteringMode', {
  86.         0: 'Unidentified',
  87.         1: 'Average',
  88.         2: 'CenterWeightedAverage',
  89.         3: 'Spot',
  90.         4: 'MultiSpot' }),
  91.     37384: ('LightSource', {
  92.         0: 'Unknown',
  93.         1: 'Daylight',
  94.         2: 'Fluorescent',
  95.         3: 'Tungsten',
  96.         10: 'Flash',
  97.         17: 'Standard Light A',
  98.         18: 'Standard Light B',
  99.         19: 'Standard Light C',
  100.         20: 'D55',
  101.         21: 'D65',
  102.         22: 'D75',
  103.         255: 'Other' }),
  104.     37385: ('Flash', {
  105.         0: 'No',
  106.         1: 'Fired',
  107.         5: 'Fired (?)',
  108.         7: 'Fired (!)',
  109.         9: 'Fill Fired',
  110.         13: 'Fill Fired (?)',
  111.         15: 'Fill Fired (!)',
  112.         16: 'Off',
  113.         24: 'Auto Off',
  114.         25: 'Auto Fired',
  115.         29: 'Auto Fired (?)',
  116.         31: 'Auto Fired (!)',
  117.         32: 'Not Available' }),
  118.     37386: ('FocalLength',),
  119.     37500: ('MakerNote',),
  120.     37510: ('UserComment', (lambda x: ''.join(map(chr, x)))),
  121.     37520: ('SubSecTime',),
  122.     37521: ('SubSecTimeOriginal',),
  123.     37522: ('SubSecTimeDigitized',),
  124.     40960: ('FlashPixVersion', (lambda x: ''.join(map(chr, x)))),
  125.     40961: ('ColorSpace',),
  126.     40962: ('ExifImageWidth',),
  127.     40963: ('ExifImageLength',),
  128.     40965: ('InteroperabilityOffset',),
  129.     41483: ('FlashEnergy',),
  130.     41484: ('SpatialFrequencyResponse',),
  131.     41486: ('FocalPlaneXResolution',),
  132.     41487: ('FocalPlaneYResolution',),
  133.     41488: ('FocalPlaneResolutionUnit',),
  134.     41492: ('SubjectLocation',),
  135.     41493: ('ExposureIndex',),
  136.     41495: ('SensingMethod',),
  137.     41728: ('FileSource', {
  138.         3: 'Digital Camera' }),
  139.     41729: ('SceneType', {
  140.         1: 'Directly Photographed' }) }
  141. INTR_TAGS = {
  142.     1: ('InteroperabilityIndex',),
  143.     2: ('InteroperabilityVersion',),
  144.     4096: ('RelatedImageFileFormat',),
  145.     4097: ('RelatedImageWidth',),
  146.     4098: ('RelatedImageLength',) }
  147. GPS_TAGS = {
  148.     0: ('GPSVersionID',),
  149.     1: ('GPSLatitudeRef',),
  150.     2: ('GPSLatitude',),
  151.     3: ('GPSLongitudeRef',),
  152.     4: ('GPSLongitude',),
  153.     5: ('GPSAltitudeRef',),
  154.     6: ('GPSAltitude',),
  155.     7: ('GPSTimeStamp',),
  156.     8: ('GPSSatellites',),
  157.     9: ('GPSStatus',),
  158.     10: ('GPSMeasureMode',),
  159.     11: ('GPSDOP',),
  160.     12: ('GPSSpeedRef',),
  161.     13: ('GPSSpeed',),
  162.     14: ('GPSTrackRef',),
  163.     15: ('GPSTrack',),
  164.     16: ('GPSImgDirectionRef',),
  165.     17: ('GPSImgDirection',),
  166.     18: ('GPSMapDatum',),
  167.     19: ('GPSDestLatitudeRef',),
  168.     20: ('GPSDestLatitude',),
  169.     21: ('GPSDestLongitudeRef',),
  170.     22: ('GPSDestLongitude',),
  171.     23: ('GPSDestBearingRef',),
  172.     24: ('GPSDestBearing',),
  173.     25: ('GPSDestDistanceRef',),
  174.     26: ('GPSDestDistance',) }
  175. MAKERNOTE_NIKON_NEWER_TAGS = {
  176.     2: ('ISOSetting',),
  177.     3: ('ColorMode',),
  178.     4: ('Quality',),
  179.     5: ('Whitebalance',),
  180.     6: ('ImageSharpening',),
  181.     7: ('FocusMode',),
  182.     8: ('FlashSetting',),
  183.     15: ('ISOSelection',),
  184.     128: ('ImageAdjustment',),
  185.     130: ('AuxiliaryLens',),
  186.     133: ('ManualFocusDistance',),
  187.     134: ('DigitalZoomFactor',),
  188.     136: ('AFFocusPosition', {
  189.         0: 'Center',
  190.         256: 'Top',
  191.         512: 'Bottom',
  192.         768: 'Left',
  193.         1024: 'Right' }),
  194.     148: ('Saturation', {
  195.         -3: 'B&W',
  196.         -2: '-2',
  197.         -1: '-1',
  198.         0: '0',
  199.         1: '1',
  200.         2: '2' }),
  201.     149: ('NoiseReduction',),
  202.     16: ('DataDump',) }
  203. MAKERNOTE_NIKON_OLDER_TAGS = {
  204.     3: ('Quality', {
  205.         1: 'VGA Basic',
  206.         2: 'VGA Normal',
  207.         3: 'VGA Fine',
  208.         4: 'SXGA Basic',
  209.         5: 'SXGA Normal',
  210.         6: 'SXGA Fine' }),
  211.     4: ('ColorMode', {
  212.         1: 'Color',
  213.         2: 'Monochrome' }),
  214.     5: ('ImageAdjustment', {
  215.         0: 'Normal',
  216.         1: 'Bright+',
  217.         2: 'Bright-',
  218.         3: 'Contrast+',
  219.         4: 'Contrast-' }),
  220.     6: ('CCDSpeed', {
  221.         0: 'ISO 80',
  222.         2: 'ISO 160',
  223.         4: 'ISO 320',
  224.         5: 'ISO 100' }),
  225.     7: ('WhiteBalance', {
  226.         0: 'Auto',
  227.         1: 'Preset',
  228.         2: 'Daylight',
  229.         3: 'Incandescent',
  230.         4: 'Fluorescent',
  231.         5: 'Cloudy',
  232.         6: 'Speed Light' }) }
  233.  
  234. def olympus_special_mode(v):
  235.     a = {
  236.         0: 'Normal',
  237.         1: 'Unknown',
  238.         2: 'Fast',
  239.         3: 'Panorama' }
  240.     b = {
  241.         0: 'Non-panoramic',
  242.         1: 'Left to right',
  243.         2: 'Right to left',
  244.         3: 'Bottom to top',
  245.         4: 'Top to bottom' }
  246.     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
  247.  
  248. MAKERNOTE_OLYMPUS_TAGS = {
  249.     256: ('JPEGThumbnail',),
  250.     512: ('SpecialMode', olympus_special_mode),
  251.     513: ('JPEGQual', {
  252.         1: 'SQ',
  253.         2: 'HQ',
  254.         3: 'SHQ' }),
  255.     514: ('Macro', {
  256.         0: 'Normal',
  257.         1: 'Macro' }),
  258.     516: ('DigitalZoom',),
  259.     519: ('SoftwareRelease',),
  260.     520: ('PictureInfo',),
  261.     521: ('CameraID', (lambda x: ''.join(map(chr, x)))),
  262.     3840: ('DataDump',) }
  263. MAKERNOTE_CASIO_TAGS = {
  264.     1: ('RecordingMode', {
  265.         1: 'Single Shutter',
  266.         2: 'Panorama',
  267.         3: 'Night Scene',
  268.         4: 'Portrait',
  269.         5: 'Landscape' }),
  270.     2: ('Quality', {
  271.         1: 'Economy',
  272.         2: 'Normal',
  273.         3: 'Fine' }),
  274.     3: ('FocusingMode', {
  275.         2: 'Macro',
  276.         3: 'Auto Focus',
  277.         4: 'Manual Focus',
  278.         5: 'Infinity' }),
  279.     4: ('FlashMode', {
  280.         1: 'Auto',
  281.         2: 'On',
  282.         3: 'Off',
  283.         4: 'Red Eye Reduction' }),
  284.     5: ('FlashIntensity', {
  285.         11: 'Weak',
  286.         13: 'Normal',
  287.         15: 'Strong' }),
  288.     6: ('Object Distance',),
  289.     7: ('WhiteBalance', {
  290.         1: 'Auto',
  291.         2: 'Tungsten',
  292.         3: 'Daylight',
  293.         4: 'Fluorescent',
  294.         5: 'Shade',
  295.         129: 'Manual' }),
  296.     11: ('Sharpness', {
  297.         0: 'Normal',
  298.         1: 'Soft',
  299.         2: 'Hard' }),
  300.     12: ('Contrast', {
  301.         0: 'Normal',
  302.         1: 'Low',
  303.         2: 'High' }),
  304.     13: ('Saturation', {
  305.         0: 'Normal',
  306.         1: 'Low',
  307.         2: 'High' }),
  308.     20: ('CCDSpeed', {
  309.         64: 'Normal',
  310.         80: 'Normal',
  311.         100: 'High',
  312.         125: '+1.0',
  313.         244: '+3.0',
  314.         250: '+2.0' }) }
  315. MAKERNOTE_FUJIFILM_TAGS = {
  316.     0: ('NoteVersion', (lambda x: ''.join(map(chr, x)))),
  317.     4096: ('Quality',),
  318.     4097: ('Sharpness', {
  319.         1: 'Soft',
  320.         2: 'Soft',
  321.         3: 'Normal',
  322.         4: 'Hard',
  323.         5: 'Hard' }),
  324.     4098: ('WhiteBalance', {
  325.         0: 'Auto',
  326.         256: 'Daylight',
  327.         512: 'Cloudy',
  328.         768: 'DaylightColor-Fluorescent',
  329.         769: 'DaywhiteColor-Fluorescent',
  330.         770: 'White-Fluorescent',
  331.         1024: 'Incandescent',
  332.         3840: 'Custom' }),
  333.     4099: ('Color', {
  334.         0: 'Normal',
  335.         256: 'High',
  336.         512: 'Low' }),
  337.     4100: ('Tone', {
  338.         0: 'Normal',
  339.         256: 'High',
  340.         512: 'Low' }),
  341.     4112: ('FlashMode', {
  342.         0: 'Auto',
  343.         1: 'On',
  344.         2: 'Off',
  345.         3: 'Red Eye Reduction' }),
  346.     4113: ('FlashStrength',),
  347.     4128: ('Macro', {
  348.         0: 'Off',
  349.         1: 'On' }),
  350.     4129: ('FocusMode', {
  351.         0: 'Auto',
  352.         1: 'Manual' }),
  353.     4144: ('SlowSync', {
  354.         0: 'Off',
  355.         1: 'On' }),
  356.     4145: ('PictureMode', {
  357.         0: 'Auto',
  358.         1: 'Portrait',
  359.         2: 'Landscape',
  360.         4: 'Sports',
  361.         5: 'Night',
  362.         6: 'Program AE',
  363.         256: 'Aperture Priority AE',
  364.         512: 'Shutter Priority AE',
  365.         768: 'Manual Exposure' }),
  366.     4352: ('MotorOrBracket', {
  367.         0: 'Off',
  368.         1: 'On' }),
  369.     4864: ('BlurWarning', {
  370.         0: 'Off',
  371.         1: 'On' }),
  372.     4865: ('FocusWarning', {
  373.         0: 'Off',
  374.         1: 'On' }),
  375.     4866: ('AEWarning', {
  376.         0: 'Off',
  377.         1: 'On' }) }
  378. MAKERNOTE_CANON_TAGS = {
  379.     6: ('ImageType',),
  380.     7: ('FirmwareVersion',),
  381.     8: ('ImageNumber',),
  382.     9: ('OwnerName',) }
  383. MAKERNOTE_CANON_TAG_0x001 = {
  384.     1: ('Macromode', {
  385.         1: 'Macro',
  386.         2: 'Normal' }),
  387.     2: ('SelfTimer',),
  388.     3: ('Quality', {
  389.         2: 'Normal',
  390.         3: 'Fine',
  391.         5: 'Superfine' }),
  392.     4: ('FlashMode', {
  393.         0: 'Flash Not Fired',
  394.         1: 'Auto',
  395.         2: 'On',
  396.         3: 'Red-Eye Reduction',
  397.         4: 'Slow Synchro',
  398.         5: 'Auto + Red-Eye Reduction',
  399.         6: 'On + Red-Eye Reduction',
  400.         16: 'external flash' }),
  401.     5: ('ContinuousDriveMode', {
  402.         0: 'Single Or Timer',
  403.         1: 'Continuous' }),
  404.     7: ('FocusMode', {
  405.         0: 'One-Shot',
  406.         1: 'AI Servo',
  407.         2: 'AI Focus',
  408.         3: 'MF',
  409.         4: 'Single',
  410.         5: 'Continuous',
  411.         6: 'MF' }),
  412.     10: ('ImageSize', {
  413.         0: 'Large',
  414.         1: 'Medium',
  415.         2: 'Small' }),
  416.     11: ('EasyShootingMode', {
  417.         0: 'Full Auto',
  418.         1: 'Manual',
  419.         2: 'Landscape',
  420.         3: 'Fast Shutter',
  421.         4: 'Slow Shutter',
  422.         5: 'Night',
  423.         6: 'B&W',
  424.         7: 'Sepia',
  425.         8: 'Portrait',
  426.         9: 'Sports',
  427.         10: 'Macro/Close-Up',
  428.         11: 'Pan Focus' }),
  429.     12: ('DigitalZoom', {
  430.         0: 'None',
  431.         1: '2x',
  432.         2: '4x' }),
  433.     13: ('Contrast', {
  434.         65535: 'Low',
  435.         0: 'Normal',
  436.         1: 'High' }),
  437.     14: ('Saturation', {
  438.         65535: 'Low',
  439.         0: 'Normal',
  440.         1: 'High' }),
  441.     15: ('Sharpness', {
  442.         65535: 'Low',
  443.         0: 'Normal',
  444.         1: 'High' }),
  445.     16: ('ISO', {
  446.         0: 'See ISOSpeedRatings Tag',
  447.         15: 'Auto',
  448.         16: '50',
  449.         17: '100',
  450.         18: '200',
  451.         19: '400' }),
  452.     17: ('MeteringMode', {
  453.         3: 'Evaluative',
  454.         4: 'Partial',
  455.         5: 'Center-weighted' }),
  456.     18: ('FocusType', {
  457.         0: 'Manual',
  458.         1: 'Auto',
  459.         3: 'Close-Up (Macro)',
  460.         8: 'Locked (Pan Mode)' }),
  461.     19: ('AFPointSelected', {
  462.         12288: 'None (MF)',
  463.         12289: 'Auto-Selected',
  464.         12290: 'Right',
  465.         12291: 'Center',
  466.         12292: 'Left' }),
  467.     20: ('ExposureMode', {
  468.         0: 'Easy Shooting',
  469.         1: 'Program',
  470.         2: 'Tv-priority',
  471.         3: 'Av-priority',
  472.         4: 'Manual',
  473.         5: 'A-DEP' }),
  474.     23: ('LongFocalLengthOfLensInFocalUnits',),
  475.     24: ('ShortFocalLengthOfLensInFocalUnits',),
  476.     25: ('FocalUnitsPerMM',),
  477.     28: ('FlashActivity', {
  478.         0: 'Did Not Fire',
  479.         1: 'Fired' }),
  480.     29: ('FlashDetails', {
  481.         14: 'External E-TTL',
  482.         13: 'Internal Flash',
  483.         11: 'FP Sync Used',
  484.         7: '2nd("Rear")-Curtain Sync Used',
  485.         4: 'FP Sync Enabled' }),
  486.     32: ('FocusMode', {
  487.         0: 'Single',
  488.         1: 'Continuous' }) }
  489. MAKERNOTE_CANON_TAG_0x004 = {
  490.     7: ('WhiteBalance', {
  491.         0: 'Auto',
  492.         1: 'Sunny',
  493.         2: 'Cloudy',
  494.         3: 'Tungsten',
  495.         4: 'Fluorescent',
  496.         5: 'Flash',
  497.         6: 'Custom' }),
  498.     9: ('SequenceNumber',),
  499.     14: ('AFPointUsed',),
  500.     15: ('FlashBias', {
  501.         65472: '-2 EV',
  502.         65484: '-1.67 EV',
  503.         65488: '-1.50 EV',
  504.         65492: '-1.33 EV',
  505.         65504: '-1 EV',
  506.         65516: '-0.67 EV',
  507.         65520: '-0.50 EV',
  508.         65524: '-0.33 EV',
  509.         0: '0 EV',
  510.         12: '0.33 EV',
  511.         16: '0.50 EV',
  512.         20: '0.67 EV',
  513.         32: '1 EV',
  514.         44: '1.33 EV',
  515.         48: '1.50 EV',
  516.         52: '1.67 EV',
  517.         64: '2 EV' }),
  518.     19: ('SubjectDistance',) }
  519.  
  520. def s2n_motorola(str):
  521.     x = 0
  522.     for c in str:
  523.         x = x << 8 | ord(c)
  524.     
  525.     return x
  526.  
  527.  
  528. def s2n_intel(str):
  529.     x = 0
  530.     y = 0x0L
  531.     for c in str:
  532.         x = x | ord(c) << y
  533.         y = y + 8
  534.     
  535.     return x
  536.  
  537.  
  538. def gcd(a, b):
  539.     if b == 0:
  540.         return a
  541.     return gcd(b, a % b)
  542.  
  543.  
  544. class Ratio:
  545.     
  546.     def __init__(self, num, den):
  547.         self.num = num
  548.         self.den = den
  549.  
  550.     
  551.     def __repr__(self):
  552.         self.reduce()
  553.         if self.den == 1:
  554.             return str(self.num)
  555.         return '%d/%d' % (self.num, self.den)
  556.  
  557.     
  558.     def reduce(self):
  559.         div = gcd(self.num, self.den)
  560.         if div > 1:
  561.             self.num = self.num / div
  562.             self.den = self.den / div
  563.         
  564.  
  565.  
  566.  
  567. class IFD_Tag:
  568.     
  569.     def __init__(self, printable, tag, field_type, values, field_offset, field_length):
  570.         self.printable = printable
  571.         self.tag = tag
  572.         self.field_type = field_type
  573.         self.field_offset = field_offset
  574.         self.field_length = field_length
  575.         self.values = values
  576.  
  577.     
  578.     def __str__(self):
  579.         return self.printable
  580.  
  581.     
  582.     def __repr__(self):
  583.         return '(0x%04X) %s=%s @ %d' % (self.tag, FIELD_TYPES[self.field_type][2], self.printable, self.field_offset)
  584.  
  585.  
  586.  
  587. class EXIF_header:
  588.     
  589.     def __init__(self, file, endian, offset, debug = 0):
  590.         self.file = file
  591.         self.endian = endian
  592.         self.offset = offset
  593.         self.debug = debug
  594.         self.tags = { }
  595.  
  596.     
  597.     def s2n(self, offset, length, signed = 0):
  598.         self.file.seek(self.offset + offset)
  599.         slice = self.file.read(length)
  600.         if self.endian == 'I':
  601.             val = s2n_intel(slice)
  602.         else:
  603.             val = s2n_motorola(slice)
  604.         if signed:
  605.             pass
  606.         
  607.         return val
  608.  
  609.     
  610.     def n2s(self, offset, length):
  611.         s = ''
  612.         for i in range(length):
  613.             if self.endian == 'I':
  614.                 s = s + chr(offset & 255)
  615.             else:
  616.                 s = chr(offset & 255) + s
  617.             offset = offset >> 8
  618.         
  619.         return s
  620.  
  621.     
  622.     def first_IFD(self):
  623.         return self.s2n(4, 4)
  624.  
  625.     
  626.     def next_IFD(self, ifd):
  627.         entries = self.s2n(ifd, 2)
  628.         return self.s2n(ifd + 2 + 12 * entries, 4)
  629.  
  630.     
  631.     def list_IFDs(self):
  632.         i = self.first_IFD()
  633.         a = []
  634.         while i:
  635.             a.append(i)
  636.             i = self.next_IFD(i)
  637.         return a
  638.  
  639.     
  640.     def dump_IFD(self, ifd, ifd_name, dict = EXIF_TAGS):
  641.         entries = self.s2n(ifd, 2)
  642.         for i in range(entries):
  643.             entry = ifd + 2 + 12 * i
  644.             tag = self.s2n(entry, 2)
  645.             field_type = self.s2n(entry + 2, 2)
  646.             if field_type < field_type:
  647.                 pass
  648.             elif not field_type < len(FIELD_TYPES):
  649.                 raise ValueError, 'unknown type %d in tag 0x%04X' % (field_type, tag)
  650.             
  651.             typelen = FIELD_TYPES[field_type][0]
  652.             count = self.s2n(entry + 4, 4)
  653.             offset = entry + 8
  654.             if count * typelen > 4:
  655.                 offset = self.s2n(offset, 4)
  656.             
  657.             field_offset = offset
  658.             if field_type == 2:
  659.                 if count != 0:
  660.                     self.file.seek(self.offset + offset)
  661.                     values = self.file.read(count).strip().replace('\x00', '')
  662.                 else:
  663.                     values = ''
  664.             else:
  665.                 values = []
  666.                 signed = field_type in (6, 8, 9, 10)
  667.                 for j in range(count):
  668.                     if field_type in (5, 10):
  669.                         value_j = Ratio(self.s2n(offset, 4, signed), self.s2n(offset + 4, 4, signed))
  670.                     else:
  671.                         value_j = self.s2n(offset, typelen, signed)
  672.                     values.append(value_j)
  673.                     offset = offset + typelen
  674.                 
  675.             if count == 1 and field_type != 2:
  676.                 printable = str(values[0])
  677.             else:
  678.                 printable = str(values)
  679.             tag_entry = dict.get(tag)
  680.             if tag_entry:
  681.                 tag_name = tag_entry[0]
  682.                 if len(tag_entry) != 1:
  683.                     if callable(tag_entry[1]):
  684.                         printable = tag_entry[1](values)
  685.                     else:
  686.                         printable = ''
  687.                         for i in values:
  688.                             printable += tag_entry[1].get(i, repr(i))
  689.                         
  690.                 
  691.             else:
  692.                 tag_name = 'Tag 0x%04X' % tag
  693.             self.tags[ifd_name + ' ' + tag_name] = IFD_Tag(printable, tag, field_type, values, field_offset, count * typelen)
  694.             if self.debug:
  695.                 print '    %s: %s' % (tag_name, repr(self.tags[ifd_name + ' ' + tag_name]))
  696.                 continue
  697.         
  698.  
  699.     
  700.     def extract_TIFF_thumbnail(self, thumb_ifd):
  701.         entries = self.s2n(thumb_ifd, 2)
  702.         if self.endian == 'M':
  703.             tiff = 'MM\x00*\x00\x00\x00\x08'
  704.         else:
  705.             tiff = 'II*\x00\x08\x00\x00\x00'
  706.         self.file.seek(self.offset + thumb_ifd)
  707.         tiff += self.file.read(entries * 12 + 2) + '\x00\x00\x00\x00'
  708.         for i in range(entries):
  709.             entry = thumb_ifd + 2 + 12 * i
  710.             tag = self.s2n(entry, 2)
  711.             field_type = self.s2n(entry + 2, 2)
  712.             typelen = FIELD_TYPES[field_type][0]
  713.             count = self.s2n(entry + 4, 4)
  714.             oldoff = self.s2n(entry + 8, 4)
  715.             ptr = i * 12 + 18
  716.             if tag == 273:
  717.                 strip_off = ptr
  718.                 strip_len = count * typelen
  719.             
  720.             if count * typelen > 4:
  721.                 newoff = len(tiff)
  722.                 tiff = tiff[:ptr] + self.n2s(newoff, 4) + tiff[ptr + 4:]
  723.                 if tag == 273:
  724.                     strip_off = newoff
  725.                     strip_len = 4
  726.                 
  727.                 self.file.seek(self.offset + oldoff)
  728.                 tiff += self.file.read(count * typelen)
  729.                 continue
  730.         
  731.         old_offsets = self.tags['Thumbnail StripOffsets'].values
  732.         old_counts = self.tags['Thumbnail StripByteCounts'].values
  733.         for i in range(len(old_offsets)):
  734.             offset = self.n2s(len(tiff), strip_len)
  735.             tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:]
  736.             strip_off += strip_len
  737.             self.file.seek(self.offset + old_offsets[i])
  738.             tiff += self.file.read(old_counts[i])
  739.         
  740.         self.tags['TIFFThumbnail'] = tiff
  741.  
  742.     
  743.     def decode_maker_note(self):
  744.         note = self.tags['EXIF MakerNote']
  745.         make = self.tags['Image Make'].printable
  746.         model = self.tags['Image Model'].printable
  747.         if make == 'NIKON':
  748.             if note.values[0:5] == [
  749.                 78,
  750.                 105,
  751.                 107,
  752.                 111,
  753.                 110]:
  754.                 self.dump_IFD(note.field_offset + 8, 'MakerNote', dict = MAKERNOTE_NIKON_OLDER_TAGS)
  755.             else:
  756.                 self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_NIKON_NEWER_TAGS)
  757.             return None
  758.         if make[:7] == 'OLYMPUS':
  759.             self.dump_IFD(note.field_offset + 8, 'MakerNote', dict = MAKERNOTE_OLYMPUS_TAGS)
  760.             return None
  761.         if make == 'Casio':
  762.             self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_CASIO_TAGS)
  763.             return None
  764.         if make == 'FUJIFILM':
  765.             endian = self.endian
  766.             self.endian = 'I'
  767.             offset = self.offset
  768.             self.offset += note.field_offset
  769.             self.dump_IFD(12, 'MakerNote', dict = MAKERNOTE_FUJIFILM_TAGS)
  770.             self.endian = endian
  771.             self.offset = offset
  772.             return None
  773.         if make == 'Canon':
  774.             self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_CANON_TAGS)
  775.             for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001), ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
  776.                 self.canon_decode_tag(self.tags[i[0]].values, i[1])
  777.             
  778.             return None
  779.  
  780.     
  781.     def canon_decode_tag(self, value, dict):
  782.         for i in range(1, len(value)):
  783.             x = dict.get(i, ('Unknown',))
  784.             if self.debug:
  785.                 print i, x
  786.             
  787.             name = x[0]
  788.             if len(x) > 1:
  789.                 val = x[1].get(value[i], 'Unknown')
  790.             else:
  791.                 val = value[i]
  792.             self.tags['MakerNote ' + name] = IFD_Tag(str(val), None, 0, None, None, None)
  793.         
  794.  
  795.  
  796.  
  797. def process_file(file, debug = 0):
  798.     data = file.read(12)
  799.     None if data[0:4] in ('II*\x00', 'MM\x00*') else data[6:10] == 'Exif'
  800.     return { }
  801.     if debug:
  802.         print {
  803.             'I': 'Intel',
  804.             'M': 'Motorola' }[endian], 'format'
  805.     
  806.     hdr = EXIF_header(file, endian, offset, debug)
  807.     ifd_list = hdr.list_IFDs()
  808.     ctr = 0
  809.     for i in ifd_list:
  810.         if ctr == 0:
  811.             IFD_name = 'Image'
  812.         elif ctr == 1:
  813.             IFD_name = 'Thumbnail'
  814.             thumb_ifd = i
  815.         else:
  816.             IFD_name = 'IFD %d' % ctr
  817.         if debug:
  818.             print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
  819.         
  820.         hdr.dump_IFD(i, IFD_name)
  821.         exif_off = hdr.tags.get(IFD_name + ' ExifOffset')
  822.         if exif_off:
  823.             if debug:
  824.                 print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
  825.             
  826.             hdr.dump_IFD(exif_off.values[0], 'EXIF')
  827.             intr_off = hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
  828.             if intr_off:
  829.                 if debug:
  830.                     print ' EXIF Interoperability SubSubIFD at offset %d:' % intr_off.values[0]
  831.                 
  832.                 hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability', dict = INTR_TAGS)
  833.             
  834.         
  835.         gps_off = hdr.tags.get(IFD_name + ' GPSInfo')
  836.         if gps_off:
  837.             if debug:
  838.                 print ' GPS SubIFD at offset %d:' % gps_off.values[0]
  839.             
  840.             hdr.dump_IFD(gps_off.values[0], 'GPS', dict = GPS_TAGS)
  841.         
  842.         ctr += 1
  843.     
  844.     thumb = hdr.tags.get('Thumbnail Compression')
  845.     if thumb and thumb.printable == 'Uncompressed TIFF':
  846.         hdr.extract_TIFF_thumbnail(thumb_ifd)
  847.     
  848.     thumb_off = hdr.tags.get('Thumbnail JPEGInterchangeFormat')
  849.     if thumb_off:
  850.         file.seek(offset + thumb_off.values[0])
  851.         size = hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
  852.         hdr.tags['JPEGThumbnail'] = file.read(size)
  853.     
  854.     if hdr.tags.has_key('EXIF MakerNote'):
  855.         hdr.decode_maker_note()
  856.     
  857.     if not hdr.tags.has_key('JPEGThumbnail'):
  858.         thumb_off = hdr.tags.get('MakerNote JPEGThumbnail')
  859.         if thumb_off:
  860.             file.seek(offset + thumb_off.values[0])
  861.             hdr.tags['JPEGThumbnail'] = file.read(thumb_off.field_length)
  862.         
  863.     
  864.     return hdr.tags
  865.  
  866. if __name__ == '__main__':
  867.     import sys
  868.     if len(sys.argv) < 2:
  869.         print 'Usage: %s files...\n' % sys.argv[0]
  870.         sys.exit(0)
  871.     
  872.     for filename in sys.argv[1:]:
  873.         
  874.         try:
  875.             file = open(filename, 'rb')
  876.         except:
  877.             print filename, 'unreadable'
  878.             print 
  879.             continue
  880.  
  881.         print filename + ':'
  882.         data = process_file(file)
  883.         if not data:
  884.             print 'No EXIF information found'
  885.             continue
  886.         
  887.         x = data.keys()
  888.         x.sort()
  889.         for i in x:
  890.             if i in ('JPEGThumbnail', 'TIFFThumbnail'):
  891.                 continue
  892.             
  893.             
  894.             try:
  895.                 print '   %s (%s): %s' % (i, FIELD_TYPES[data[i].field_type][2], data[i].printable)
  896.             continue
  897.             print 'error', i, '"', data[i], '"'
  898.             continue
  899.  
  900.         
  901.         if data.has_key('JPEGThumbnail'):
  902.             print 'File has JPEG thumbnail'
  903.         
  904.         print 
  905.     
  906.  
  907.